package org.hako.recite.word;

import java.io.PrintWriter;

import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.hako.recite.word.parser.WordListParseException;
import org.hako.recite.word.parser.impl.UnsupportedFileExtensionException;
import org.hako.recite.word.test.WordTest;
import org.hako.recite.word.test.WordTestDisplayMode;
import org.hako.recite.word.test.WordTestFactory;
import org.hako.recite.word.test.WordTestProfile;

/**
 * Program entry point.
 * 
 * @author xnnyygn
 */
public class CommandLine {

	/**
	 * Main method.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		CommandLineParser parser = new PosixParser();
		Options options = createOptions();
		try {
			org.apache.commons.cli.CommandLine line = parser.parse(options,
					args, true);
			String filePath = line.getOptionValue("file");
			WordTestProfile profile = generateTestProfile(parser.parse(options,
					args));
			WordTestDisplayMode displayMode = parseDisplayMode(line);
			WordTest wordTest = createTest(filePath, profile, displayMode);
			if (WordTestDisplayMode.CONSOLE.equals(displayMode)) {
				showTestSummary(profile);
			}
			wordTest.start();
		} catch (ParseException e) {
			showHelp(options);
		} catch (NumberFormatException e) {
			System.err.println(e.getMessage());
		} catch (WordListParseException e) {
			System.err.println(e.getMessage());
		} catch (UnsupportedFileExtensionException e) {
			System.err.println(e.getMessage());
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println(e.getMessage());
		}
	}

	/**
	 * Parse word test display mode from command line.
	 * 
	 * @param line
	 */
	private static WordTestDisplayMode parseDisplayMode(
			org.apache.commons.cli.CommandLine line) {
		if (line.hasOption("displayMode")) {
			try {
				return WordTestDisplayMode.valueOf(line.getOptionValue(
						"displayMode").toUpperCase());
			} catch (IllegalArgumentException e) {

				// omit error
			}
		}
		return WordTestDisplayMode.CONSOLE;
	}

	/**
	 * Show usage and help.
	 * 
	 * @param options
	 */
	private static void showHelp(Options options) {
		HelpFormatter formatter = new HelpFormatter();
		PrintWriter writer = new PrintWriter(System.out);
		formatter.printHelp(writer, 80, "java -jar recite-word-xxx.jar",
				"Recite Word JP Help", options, 3, 5, "", true);
		writer.flush();
	}

	/**
	 * Create word test.
	 * 
	 * @param filePath
	 * @param profile
	 * @param displayMode
	 * @throws WordListParseException
	 * @throws UnsupportedFileExtensionException
	 */
	private static WordTest createTest(String filePath,
			WordTestProfile profile, WordTestDisplayMode displayMode)
			throws WordListParseException, UnsupportedFileExtensionException {
		WordTestFactory factory = new WordTestFactory();
		return factory.create(filePath, profile, displayMode);
	}

	/**
	 * Create options.
	 * 
	 * @return
	 * @throws IllegalArgumentException
	 */
	private static Options createOptions() throws IllegalArgumentException {
		Options options = new Options();
		Option fileOption = new Option("f", "file", true,
				"file contains test words, required");
		fileOption.setRequired(true);
		options.addOption(fileOption);
		options.addOption("dm", "displayMode", true, "display mode, "
				+ "available values is console, swing, swt, "
				+ "default is console,"
				+ "and if your os is windows, recite word will automaticllay "
				+ "change display mode to swt");
		options.addOption("m", "testMode", true,
				"test mode, 0 is LEARNING MODE, "
						+ "1 is TEST MODE, default is 0(LEARNING MODE)");
		options.addOption("l", "limit", true,
				"limit of test word, default is 10");
		options.addOption("o", "offset", true, "offset of test word, "
				+ "default is 0. ATTENTION: "
				+ "offset is ignored if use TEST mode");
		options.addOption("rs", "rangeStart", true,
				"range start of word in test mode, default is 0, "
						+ "ATTENTION, range start is ignored in LEARNING mode");
		options.addOption("re", "rangeEnd", true,
				"range end of word in test mode, default is word count, "
						+ "ATTENTION: range end is ignored in learning mode");
		options.addOption("qfi", "questionFieldIndex", true,
				"field index of question, default is 0(first column)");
		options.addOption("afi", "answerFieldIndex", true,
				"field index of answer, default is 1(second column)");
		options.addOption("drw", "disableRetestWrongs", false,
				"disable retest wrongs feature");
		return options;
	}

	/**
	 * Generate test profile.
	 * 
	 * @param line
	 * @return
	 * @throws NumberFormatException
	 */
	private static WordTestProfile generateTestProfile(
			org.apache.commons.cli.CommandLine line)
			throws NumberFormatException {
		WordTestProfile profile = new WordTestProfile();
		if (line.hasOption("testMode")) {
			profile.setRandomMode(Integer.parseInt(line
					.getOptionValue("testMode")));
		}
		if (line.hasOption("limit")) {
			profile.setWordLimit(Integer.parseInt(line.getOptionValue("limit")));
		}
		if (line.hasOption("offset")) {
			profile.setWordOffset(Integer.parseInt(line
					.getOptionValue("offset")));
		}
		if (line.hasOption("rangeEnd")) {
			profile.setWordRangeEnd(Integer.parseInt(line
					.getOptionValue("rangeEnd")));
		}
		if (line.hasOption("rangeStart")) {
			profile.setWordRangeStart(Integer.parseInt(line
					.getOptionValue("rangeStart")));
		}
		if (line.hasOption("questionFieldIndex")) {
			profile.setQuestionFieldIndex(Integer.parseInt(line
					.getOptionValue("questionFieldIndex")));
		}
		if (line.hasOption("answerFieldIndex")) {
			profile.setAnswerFieldIndex(Integer.parseInt(line
					.getOptionValue("answerFieldIndex")));
		}
		if (line.hasOption("disableRetestWrongs")) {
			profile.setRetestWrongs(false);
		}
		return profile;
	}

	/**
	 * Show test summary.
	 * 
	 * @param profile
	 */
	private static void showTestSummary(WordTestProfile profile) {
		System.out.print(Constants.APPLICATION_NAME);
		System.out.print(' ');
		System.out.println(Constants.VERSION);
		System.out.println("=================================================");
		System.out.print("Current test mode: ");
		int randomMode = profile.getRandomMode();
		if (randomMode == 0) {
			System.out.print("LEARNING");
			System.out.print(", Word: ");
			System.out.print(profile.getWordOffset() + 1);
			System.out.print('~');
			System.out.print(profile.getWordLimit() + profile.getWordOffset());
		} else {
			System.out.print("TEST ");
			System.out.print(", Word count: ");
			System.out.print(profile.getWordLimit());
			System.out.print(", Range: ");
			System.out.print(profile.getWordRangeStart());
			System.out.print('~');
			System.out.print(profile.getWordRangeEnd());
		}
		System.out.print(", Question field: ");
		System.out.print(profile.getQuestionFieldIndex());
		System.out.print(", Answer field: ");
		System.out.print(profile.getAnswerFieldIndex());
		System.out.print(", Retest Wrongs: ");
		System.out.println(profile.isRetestWrongs() ? "ON" : "OFF");
	}
}
